﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using GRTVPluginConsole.Listener;
using GRTVPluginConsole.Entity;
using System.Net.Sockets;
using System.Net;
using System.Reflection;
using System.Diagnostics;
using GRTVPluginConsole.Utils;
using System.Globalization;
using GRTVPluginConsole.Webserver;
using GRTVPluginConsole.Camera;
using GRTVPluginConsole.UI;

namespace GRTVPluginConsole
{
    public partial class Form1 : Form
    {
        private AutoCameraEngine autoCameraEngine = null;
        private string[] tabName = new string[4] { "Drivers", "Events", "Widgets","Auto Camera" };
        private int[] unreadElement = new int[4] { 0, 0, 0, 0 };
        public List<Event> eventListModel = new List<Event>();
        public List<DriverRank> driverRanks = new List<DriverRank>();
        private System.Windows.Forms.ToolTip ToolTip1 = new System.Windows.Forms.ToolTip();
       
        private int INDEX_TAB_EVENT = 1;
        public int cbTrackLocationProviderIndex;
        TinyWebServer webServer;
        private string webPath;
        // limite max of driver list (this is used to avoid side effect when drivers leave server or when server send fake place)
        // starting at 10000 for compatibility purpose, in case of the plugin is an old version and don't send this information
        private int driverNumberToDisplay = 10000;
        public Form1()
        {
            InitializeComponent();
            Program.configuration.realtimeConfig = new RealTimeConfig(lblWeatherMessage);
            PluginListenerThread.callback = this;
            cbEventFilter.SelectedIndex = 0;
            cbCameraType.SelectedIndex = 4;
            cbCameraTypeDrivers.SelectedIndex = 5;
            cbWidget.SelectedIndex = 0;
            string s;
            for (int i = 0; i < 1000; i++)
            {
                s = "onboard" + i;
                cbCameraType.Items.Add(s);
                cbCameraTypeDrivers.Items.Add(s);
            }
            cbTrackLocationProviderIndex = -1;

            cbAutoCameraMode.SelectedIndex = 0;
            cbAutoCameraType.SelectedIndex = 5;

            //BlankForm blank = new BlankForm();
            //blank.Controls.Add(new DriverRankUI());
            //blank.Show();

            MainUI mainUI = new MainUI();
            mainUI.Show();
        }
        private void FillFakeDrivers(int nbTotalDrivers, int nbCat)
        {
            Random rnd = new Random();
            for (int i = 0; i < nbTotalDrivers; i++)
            {
                DriverRank dr = new DriverRank();
                dr.slotId = i + 1;
                dr.place = i + 1;
                dr.name = "Driver " + dr.place;
                dr.isInPit = false;
                dr.finishStatus = 0;
                dr.categoryGroup = "CAT" + (rnd.Next(nbCat) + 1);
                newDriverRank(dr);
            }
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            string AssemblyTitle = null;
            object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false);
            if (attributes.Length > 0)
            {
                AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0];
                if (titleAttribute.Title != "")
                {
                    AssemblyTitle = titleAttribute.Title;
                }
            }
            if (AssemblyTitle == null)
            {
                AssemblyTitle = System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase);
            }

            this.Text = String.Format("{0} {1} - listening on port {2}", AssemblyTitle, Assembly.GetExecutingAssembly().GetName().Version.ToString(), Program.configuration.serverPort);

            Program.configuration.realtimeConfig.picture = pictureBox1;

            ToolTip1.SetToolTip(this.ttWUAPIKey, "The free key allows you to ask weather 500 times a day, and 10 per minute max.");
            ToolTip1.SetToolTip(this.ttWUAskEvery, "Radar images are generally updated every minute.");
            ToolTip1.SetToolTip(this.ttProviderWS, "Requires rF2 Weather Server 1.1.7.0+.");

            txtrF2WSAddress.Text = Program.configuration.iniFile.IniReadValue("WeatherWidget", "rF2WeatherServer.Address", "127.0.0.1");
            txtrF2WSPort.Text = Program.configuration.iniFile.IniReadValue("WeatherWidget", "rF2WeatherServer.Port", "666");
            txtrF2WSPluginPort.Text = Program.configuration.iniFile.IniReadValue("WeatherWidget", "rF2WeatherServer.PluginPort", "12345");

            Program.configuration.realtimeConfig.wuAPIKey = Program.configuration.iniFile.IniReadValue("WeatherWidget", "WeatherUndergroundAPIKey");
            txtWUApiKey.Text = Program.configuration.realtimeConfig.wuAPIKey;
            int number;
            if (Int32.TryParse( Program.configuration.iniFile.IniReadValue("WeatherWidget", "askRadarEveryInSecond", "" + Program.configuration.realtimeConfig.askWeatherEveryInSecond), out number)) {
                Program.configuration.realtimeConfig.askWeatherEveryInSecond = number;
            }
            txtAskWUEverySeconds.Text = "" + Program.configuration.realtimeConfig.askWeatherEveryInSecond;

            cbTrackLocationProvider.SelectedIndex = Int32.Parse(Program.configuration.iniFile.IniReadValue("WeatherWidget", "ProviderLocationIndex","0"));
            decimal dNumber;
            if (Decimal.TryParse(Program.configuration.iniFile.IniReadValue("WeatherWidget", "ownLatitude").Trim(), System.Globalization.NumberStyles.Float, CultureInfo.InvariantCulture, out dNumber))
            {
                Program.configuration.realtimeConfig.ownLatitude = (double)dNumber;
                txtOwnLat.Text = Program.configuration.realtimeConfig.ownLatitude.ToString(CultureInfo.InvariantCulture);
            }
            if (Decimal.TryParse(Program.configuration.iniFile.IniReadValue("WeatherWidget", "ownLongitude").Trim(), System.Globalization.NumberStyles.Float, CultureInfo.InvariantCulture, out dNumber))
            {
                Program.configuration.realtimeConfig.ownLongitude = (double)dNumber;
                txtOwnLong.Text = Program.configuration.realtimeConfig.ownLongitude.ToString(CultureInfo.InvariantCulture);
            }

            //askSessionInformation();

            txtWebServerPort.Text = Program.configuration.iniFile.IniReadValue("WebServer", "Port", "80");
            webPath = Program.configuration.iniFile.IniReadValue("WebServer", "WebPath", "./web");

            //FillFakeDrivers(5, 3);

        }

        public void newSession()
        {
            this.Invoke((MethodInvoker)delegate
            {
                eventListModel.Clear();
                lstEvents.Items.Clear();
                tblDriverRanks.Rows.Clear();
                driverRanks.Clear();
                if (autoCameraEngine != null)
                {
                    autoCameraEngine.Reset();
                }
            });

        }

        public void newEvent(Event entity)
        { 
            this.Invoke((MethodInvoker)delegate
            {
                if (tabControl1.SelectedIndex != INDEX_TAB_EVENT)
                {
                    unreadElement[INDEX_TAB_EVENT]++;
                    tabControl1.Controls[INDEX_TAB_EVENT].Text = tabName[INDEX_TAB_EVENT] + " (" + unreadElement[INDEX_TAB_EVENT] + ")";
                    tabControl1.Controls[INDEX_TAB_EVENT].BackColor = Color.Green;
                }
                eventListModel.Add(entity);
                RebuildEventListItems();
            });
        }



        public void newDriverRank(DriverRank entity)
        { 
            this.Invoke((MethodInvoker)delegate
            {
                if (entity.place <= driverNumberToDisplay)
                {
                    if (tblDriverRanks.RowCount < entity.place)
                    {
                        for (int i = tblDriverRanks.RowCount; i < entity.place; i++)
                        {
                            tblDriverRanks.Rows.Add();
                            driverRanks.Add(null);
                        }
                    }
                    tblDriverRanks.Rows[entity.place - 1].SetValues(new object[] { entity.place, entity.categoryGroup + " - " + entity.name , entity.getStatus() });
                    driverRanks[entity.place - 1] = entity;
                }
            });
            tblDriverRanks.Invalidate();
        }









        public bool isEventOfType(Event evt, int typeIndex)
        {
            if (typeIndex <= 0)
            {
                return true;
            }
            else if (typeIndex == 1 && evt is Overtake)
            {
                return true;
            }
            else if (typeIndex == 2 && evt is FinishStatus)
            {
                return true;
            }
            else if (typeIndex == 3 && evt is OffTrackEvent)
            {
                return true;
            }
            else if (typeIndex == 4 && evt is SpinRoundEvent)
            {
                return true;
            }
            return false;
        }
        private void RebuildEventListItems()
        {
            Event selectedEvent = (Event)lstEvents.SelectedItem;
            Event evt;
            lstEvents.Items.Clear();
            for (int i = 0; i < eventListModel.Count; i++)
            {
                evt = eventListModel[i];
                
                if (isEventOfType(evt, cbEventFilter.SelectedIndex))
                {
                    lstEvents.Items.Add(evt);
                    if (evt == selectedEvent)
                    {
                        lstEvents.SelectedIndex = lstEvents.Items.Count - 1;
                    }
                }
            }
        }
        private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (unreadElement[tabControl1.SelectedIndex] != -1)
            {
                unreadElement[tabControl1.SelectedIndex] = 0;
                tabControl1.Controls[tabControl1.SelectedIndex].Text = tabName[tabControl1.SelectedIndex];
                tabControl1.Controls[tabControl1.SelectedIndex].BackColor = Color.White;
            }
        }

        private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
        {
            if (e.Index < 0 || e.Index >= tabControl1.TabPages.Count) return;
            try
            {
                TabPage page = tabControl1.TabPages[e.Index];
                if (unreadElement[e.Index] > 0)
                {
                    e.Graphics.FillRectangle(new SolidBrush(Color.Yellow), e.Bounds);
                }
                else
                {
                    e.Graphics.FillRectangle(new SolidBrush(this.BackColor), e.Bounds);
                }

                Rectangle paddedBounds = e.Bounds;
                int yOffset = (e.State == DrawItemState.Selected) ? -2 : 1;
                paddedBounds.Offset(1, yOffset);
                TextRenderer.DrawText(e.Graphics, page.Text , this.Font, paddedBounds, this.ForeColor);
                // This event is called once for each tab button in your tab control
            }
            catch (Exception ex)
            {
                //avoid crash
            }
        }

        private void lstEvents_DrawItem(object sender, DrawItemEventArgs e)
        {
            if (e.Index < 0 || e.Index >= lstEvents.Items.Count) return;
            try
            {
                Event evt = (Event)lstEvents.Items[e.Index];
                if (e.Index == lstEvents.SelectedIndex)
                {
                    e.Graphics.FillRectangle(new SolidBrush(e.BackColor), e.Bounds);
                }
                else
                {
                    if (evt.eventCreation.Ticks + 50000000 > DateTime.Now.Ticks)
                    {
                        e.Graphics.FillRectangle(new SolidBrush(Color.LightGreen), e.Bounds);
                    }
                    else if (evt.eventCreation.Ticks + 1600000000 < DateTime.Now.Ticks)
                    {
                        e.Graphics.FillRectangle(new SolidBrush(Color.Red), e.Bounds);
                    }
                    else if (evt.eventCreation.Ticks + 1300000000 < DateTime.Now.Ticks)
                    {
                        e.Graphics.FillRectangle(new SolidBrush(Color.Orange), e.Bounds);
                    }
                    else if (evt.eventCreation.Ticks + 900000000 < DateTime.Now.Ticks)
                    {
                        e.Graphics.FillRectangle(new SolidBrush(Color.LightYellow), e.Bounds);
                    }
                    else
                    {
                        e.Graphics.FillRectangle(new SolidBrush(e.BackColor), e.Bounds);
                    }
                }

                Rectangle paddedBounds = e.Bounds;
                int yOffset = (e.State == DrawItemState.Selected) ? -2 : 1;
                paddedBounds.Offset(1, yOffset);
                TextRenderer.DrawText(e.Graphics, evt.ToString(), this.Font, paddedBounds, Color.Black, TextFormatFlags.Left | TextFormatFlags.SingleLine | TextFormatFlags.GlyphOverhangPadding | TextFormatFlags.VerticalCenter | TextFormatFlags.WordEllipsis);
            }
            catch (Exception ex)
            {
                // just to avoid crash
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            lstEvents.Invalidate();
            bool needRebuild = false;
            for (int i = eventListModel.Count - 1; i >= 0; i--)
            {
                Event evt = (Event)eventListModel[i];
                if (evt.eventCreation.Ticks + 1800000000 < DateTime.Now.Ticks)
                {
                    needRebuild = true;
                    eventListModel.RemoveAt(i);
                }
            }
            if (needRebuild)
            {
                RebuildEventListItems();
            }

        }

        private void btReplayEvent_Click(object sender, EventArgs e)
        {
            Event evt = (Event)lstEvents.SelectedItem;
            if (evt == null) return;
            // prepare data
            //byte[] bs = new byte[17];
            //bs[0] = 1;
            //byte[] tmp = BitConverter.GetBytes(evt.slotId);
            //Buffer.BlockCopy(tmp, 0, bs, 1, 4);

            //tmp = BitConverter.GetBytes((int)(cbCameraType.SelectedIndex -1));
            //Buffer.BlockCopy(tmp, 0, bs, 5, 4);

            //double nbSecond = Int32.Parse(txtBeforeReplaySecond.Text);
            //tmp = BitConverter.GetBytes(Math.Max(0, evt.overtakeET - nbSecond));
            //Buffer.BlockCopy(tmp, 0, bs, 9, 8);
            

            //// send UDP command
            //var client = new UdpClient();
            //IPEndPoint ep = new IPEndPoint(Program.configuration.pluginAddress, Program.configuration.pluginPort);
            //client.Connect(ep);

            //// send data
            //client.Send(bs, bs.Length);
            //client.Close();
            
            int nbSecond = Int32.Parse(txtBeforeReplaySecond.Text);
            sendReplayEvent(evt.uuid, nbSecond, cbCameraType.SelectedIndex - 1);
        }

        public void sendReplayEvent(string uuid, int seconds, int cameraIndex)
        {
            Event evt = null;
            List<Event> iter = new List<Event>(eventListModel);
            for (int i = 0; i < iter.Count; i++)
            {
                if (iter[i].uuid.Equals(uuid))
                {
                    evt = iter[i];
                    break;
                }
            }
            if (evt == null) return;

            byte[] bs = new byte[17];
            bs[0] = 1;
            byte[] tmp = BitConverter.GetBytes(evt.slotId);
            Buffer.BlockCopy(tmp, 0, bs, 1, 4);

            tmp = BitConverter.GetBytes(cameraIndex);
            Buffer.BlockCopy(tmp, 0, bs, 5, 4);

            tmp = BitConverter.GetBytes(Math.Max(0, evt.overtakeET - seconds));
            Buffer.BlockCopy(tmp, 0, bs, 9, 8);


            // send UDP command
            var client = new UdpClient();
            IPEndPoint ep = new IPEndPoint(Program.configuration.pluginAddress, Program.configuration.pluginPort);
            client.Connect(ep);

            // send data
            client.Send(bs, bs.Length);
            client.Close();
        }

        private void askSessionInformation()
        {
            byte[] bs = new byte[1];
            bs[0] = 0;
            // send UDP command
            var client = new UdpClient();
            IPEndPoint ep = new IPEndPoint(Program.configuration.pluginAddress, Program.configuration.pluginPort);
            client.Connect(ep);

            // send data
            client.Send(bs, bs.Length);
            client.Close();
        }
        private void btGoLive_Click(object sender, EventArgs e)
        {
            sendGoLive();
        }
        public void sendGoLive()
        {
            byte[] bs = new byte[1];
            bs[0] = 2;
            // send UDP command
            var client = new UdpClient();
            IPEndPoint ep = new IPEndPoint(Program.configuration.pluginAddress, Program.configuration.pluginPort);
            client.Connect(ep);

            // send data
            client.Send(bs, bs.Length);
            client.Close();
        }


        private void cbEventFilter_SelectedIndexChanged(object sender, EventArgs e)
        {
            RebuildEventListItems();
        }

        private void btViewDriver_Click(object sender, EventArgs e)
        {
            if (tblDriverRanks.SelectedRows.Count <= 0) return;

            DriverRank entity = (DriverRank)driverRanks[tblDriverRanks.SelectedRows[0].Index];
            viewDriver(entity.slotId, cbCameraTypeDrivers.SelectedIndex - 1);
            
        }

        private void chkDisplayInMonitor_CheckedChanged(object sender, EventArgs e)
        {
            // prepare data
            byte commandType = 1; // display in monitor
            byte commandValue = (byte)(chkDisplayInMonitor.Checked ? 1 : 0);

            // send UDP command
            sendPluginCommand(commandType, commandValue);
        }

        private void chkPinDriverTiming_CheckedChanged(object sender, EventArgs e)
        {
            // prepare data
            byte commandType = 2; // pin Driver Timing
            byte commandValue = (byte)(chkPinDriverTiming.Checked ? 1 : 0);

            // send UDP command
            sendPluginCommand(commandType, commandValue);
        }

        private void btCycleCategory_Click(object sender, EventArgs e)
        {
            sendPluginCommand(3, 1);
        }

        private void btCycleTowerMode_Click(object sender, EventArgs e)
        {
            sendPluginCommand(4, 1);
        }
        public void sendPluginCommand(byte commandType, byte commandValue)
        {
            // prepare data
            byte[] bs = new byte[3];
            bs[0] = 4; // plugin command
            bs[1] = commandType; 
            bs[2] = commandValue;


            // send UDP command
            var client = new UdpClient();
            IPEndPoint ep = new IPEndPoint(Program.configuration.pluginAddress, Program.configuration.pluginPort);
            client.Connect(ep);

            // send data
            client.Send(bs, bs.Length);
            client.Close();
        }

        private void btWidgetShow_Click(object sender, EventArgs e)
        {
            sendWidgetVisibility((byte)cbWidget.SelectedIndex, 1);
        }
        private void btWidgetHide_Click(object sender, EventArgs e)
        {
            sendWidgetVisibility((byte)cbWidget.SelectedIndex, 0);
        }
        public void sendWidgetVisibility(byte widgetId, byte widgetVisibility)
        {
            // prepare data
            byte[] bs = new byte[3];
            bs[0] = 5; // widget visibility
            bs[1] = widgetId;
            bs[2] = widgetVisibility;


            // send UDP command
            var client = new UdpClient();
            IPEndPoint ep = new IPEndPoint(Program.configuration.pluginAddress, Program.configuration.pluginPort);
            client.Connect(ep);

            // send data
            client.Send(bs, bs.Length);
            client.Close();
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            Environment.Exit(0);
        }

        private void pictureBox2_Click(object sender, EventArgs e)
        {
            Process.Start("http://www.wunderground.com/weather/api/");
        }

        private void btApplyAPIKey_Click(object sender, EventArgs e)
        {
            Program.configuration.realtimeConfig.wuAPIKey = txtWUApiKey.Text;
            Program.configuration.iniFile.IniWriteValue("WeatherWidget", "WeatherUndergroundAPIKey", Program.configuration.realtimeConfig.wuAPIKey);
            btApplyAPIKey.Enabled = false;
            if (Program.configuration.realtimeConfig.running)
            {
                Program.configuration.realtimeConfig.StartOrRestartTimer();
            }
        }

        private void txtWUApiKey_TextChanged(object sender, EventArgs e)
        {
            if ( !txtWUApiKey.Text.Equals(Program.configuration.realtimeConfig.wuAPIKey))
            {
                btApplyAPIKey.Enabled = true;
            }
            else
            {
                btApplyAPIKey.Enabled = false;
            }
        }

        private void btApplyAskEveryS_Click(object sender, EventArgs e)
        {
            int number;
            if (Int32.TryParse(txtAskWUEverySeconds.Text, out number))
            {
                if (number > 0)
                {
                    Program.configuration.realtimeConfig.askWeatherEveryInSecond = number;
                    Program.configuration.iniFile.IniWriteValue("WeatherWidget", "askRadarEveryInSecond", "" + Program.configuration.realtimeConfig.askWeatherEveryInSecond);
                    btApplyAskEveryS.Enabled = false;
                    if (Program.configuration.realtimeConfig.running)
                    {
                        Program.configuration.realtimeConfig.StartOrRestartTimer();
                    }
                }
            }
        }

        private void txtAskWUEverySeconds_TextChanged(object sender, EventArgs e)
        {
            if (!txtAskWUEverySeconds.Text.Equals("" + Program.configuration.realtimeConfig.askWeatherEveryInSecond))
            {
                btApplyAskEveryS.Enabled = true;
            }
            else
            {
                btApplyAskEveryS.Enabled = false;
            }
        }

        private void btCallrF2WS_Click(object sender, EventArgs e)
        {
            cbTrackLocationProviderIndex = cbTrackLocationProvider.SelectedIndex;
            if ("".Equals(txtWUApiKey))
            {
                return;
            }
            try
            {
                Program.configuration.iniFile.IniWriteValue("WeatherWidget", "ProviderLocationIndex", "" + cbTrackLocationProvider.SelectedIndex);
                if (cbTrackLocationProvider.SelectedIndex == 1)
                {

                    // ask track info (lat, long)
                    var client = new UdpClient();
                    IPAddress address = IPAddress.Parse(txtrF2WSAddress.Text);
                    IPEndPoint ep = new IPEndPoint(address, Int32.Parse(txtrF2WSPort.Text));
                    int pluginPort = Int32.Parse(txtrF2WSPluginPort.Text);

                    Program.configuration.iniFile.IniWriteValue("WeatherWidget", "rF2WeatherServer.Address", txtrF2WSAddress.Text);
                    Program.configuration.iniFile.IniWriteValue("WeatherWidget", "rF2WeatherServer.Port", "" + txtrF2WSPort.Text);
                    Program.configuration.iniFile.IniWriteValue("WeatherWidget", "rF2WeatherServer.PluginPort", "" + txtrF2WSPluginPort.Text);

                    client.Connect(ep);

                    // send data
                    byte[] bs = new byte[14];
                    int index = 0;
                    byte[] b = System.Text.Encoding.ASCII.GetBytes("RF2TVi");
                    Buffer.BlockCopy(b, 0, bs, index, b.Length);
                    index += b.Length;
                    b = BitConverter.GetBytes((int)pluginPort);
                    Buffer.BlockCopy(b, 0, bs, index, b.Length);
                    index += b.Length;
                    b = BitConverter.GetBytes((int)Program.configuration.serverPort);
                    Buffer.BlockCopy(b, 0, bs, index, b.Length);
                    index += b.Length;

                    client.Send(bs, bs.Length);
                    client.Close();
                    lblWeatherMessage.Text = "Query sent to rF2 Live Weather server, waiting response...";
                }
                else if (cbTrackLocationProvider.SelectedIndex == 0)
                {
                    decimal dNumber;
                    if (Decimal.TryParse(txtOwnLat.Text.Replace(',', '.'), System.Globalization.NumberStyles.Float, CultureInfo.InvariantCulture, out dNumber))
                    {
                        Program.configuration.realtimeConfig.ownLatitude = (double)dNumber;
                        Program.configuration.iniFile.IniWriteValue("WeatherWidget", "ownLatitude", "" + Program.configuration.realtimeConfig.ownLatitude.ToString(CultureInfo.InvariantCulture));
                    }
                    else
                    {
                        lblWeatherMessage.Text = "Incorrect latitude.";
                        return;
                    }
                    if (Decimal.TryParse(txtOwnLong.Text.Replace(',', '.'), System.Globalization.NumberStyles.Float, CultureInfo.InvariantCulture, out dNumber))
                    {
                        Program.configuration.realtimeConfig.ownLongitude = (double)dNumber;
                        Program.configuration.iniFile.IniWriteValue("WeatherWidget", "ownLongitude", Program.configuration.realtimeConfig.ownLongitude.ToString(CultureInfo.InvariantCulture));
                    }
                    else
                    {
                        lblWeatherMessage.Text = "Incorrect longitude.";
                        return;
                    }

                    Program.configuration.realtimeConfig.StartOrRestartTimer();
                    btCallrF2WS.Enabled = false;
                    btStopCollectRadar.Enabled = true;
                    lblRadarCoordinate.Text = "lat= " + Program.configuration.realtimeConfig.ownLatitude.ToString(CultureInfo.InvariantCulture) + " / lon= " + Program.configuration.realtimeConfig.ownLongitude.ToString(CultureInfo.InvariantCulture) + "";
                }
                else if (cbTrackLocationProvider.SelectedIndex == 2)
                {
                    // GDB
                    lblWeatherMessage.Text = "Query sent to TV Plugin, waiting response...";
                    askSessionInformation();
                }

            }
            catch (Exception ex)
            {
                lblWeatherMessage.Text = ex.Message;
            }
        }

        private void btStopCollectRadar_Click(object sender, EventArgs e)
        {
            cbTrackLocationProviderIndex = -1;
            Program.configuration.realtimeConfig.StopTimer();
            btCallrF2WS.Enabled = true;
            btStopCollectRadar.Enabled = false;
        }

        public void reAskWeatherServer()
        {
            if (Program.configuration.realtimeConfig.running)
            {
                this.Invoke((MethodInvoker)delegate
                {
                    btStopCollectRadar_Click(null, null);
                    btCallrF2WS_Click(null, null);
                });
            }
        }

        private void cbTrackLocationProvider_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cbTrackLocationProvider.SelectedIndex == 0)
            {
                pnTrackLocProviderManual.Visible = true;
                pnTrackLocProviderWS.Visible = false;
                pnTrackLocProviderGDB.Visible = false;
            }
            else if (cbTrackLocationProvider.SelectedIndex == 1)
            {
                pnTrackLocProviderManual.Visible = false;
                pnTrackLocProviderWS.Visible = true;
                pnTrackLocProviderGDB.Visible = false;
            }
            else if (cbTrackLocationProvider.SelectedIndex == 2)
            {
                pnTrackLocProviderManual.Visible = false;
                pnTrackLocProviderWS.Visible = false;
                pnTrackLocProviderGDB.Visible = true;
            }
        }

        private void label12_Click(object sender, EventArgs e)
        {

        }

        private void lblWeatherMessage_Click(object sender, EventArgs e)
        {

        }


        internal void viewDriver(int slotId, int cameraType)
        {
            // prepare data
            byte[] bs = new byte[9];
            bs[0] = 3;
            byte[] tmp = BitConverter.GetBytes(slotId);
            Buffer.BlockCopy(tmp, 0, bs, 1, 4);

            tmp = BitConverter.GetBytes(cameraType);
            Buffer.BlockCopy(tmp, 0, bs, 5, 4);

            // send UDP command
            var client = new UdpClient();
            IPEndPoint ep = new IPEndPoint(Program.configuration.pluginAddress, Program.configuration.pluginPort);
            client.Connect(ep);

            // send data
            client.Send(bs, bs.Length);
            client.Close();
        }
         
        private void btStopWebServer_Click(object sender, EventArgs e)
        {
            webServer.StopListener();
            btStartWebServer.Enabled = true;
            btStopWebServer.Enabled = false;
        }

        private void btStartWebServer_Click(object sender, EventArgs e)
        {
            webServer = new TinyWebServer(Int32.Parse(txtWebServerPort.Text), webPath);
            btStartWebServer.Enabled = false;
            btStopWebServer.Enabled = true;
        }

        private void txtWebServerPort_TextChanged(object sender, EventArgs e)
        {
            Program.configuration.iniFile.IniWriteValue("WebServer", "Port", txtWebServerPort.Text);
        }

        internal void SetNumberOfDrivers(int driverNumberToDisplay)
        {
            this.driverNumberToDisplay = driverNumberToDisplay;
            if (driverNumberToDisplay < tblDriverRanks.RowCount)
            {
                this.Invoke((MethodInvoker)delegate
                   {
                       tblDriverRanks.RowCount = driverNumberToDisplay;
                   });
            }
        }

        private void chkGapToLeader_CheckedChanged(object sender, EventArgs e)
        {
            sendPluginCommand(5, (byte)(chkGapToLeader.Checked?1:0));
        }

        private void button1_Click(object sender, EventArgs e)
        {
             int numberFreq = 0;
             if (txtAutoFrequencySecond.Enabled && !Int32.TryParse(txtAutoFrequencySecond.Text, out numberFreq))
             {
                 return;
             }
             int numberDriver = 0;
             if (txtAutoNbDrivers.Enabled && !Int32.TryParse(txtAutoNbDrivers.Text, out numberDriver))
             {
                 return;
             }
             /*
             // prepare data
             byte[] bs = new byte[17];
             bs[0] = 6;
             byte[] tmp = BitConverter.GetBytes(cbAutoCameraMode.SelectedIndex);
             Buffer.BlockCopy(tmp, 0, bs, 1, 4);

             tmp = BitConverter.GetBytes(cbAutoCameraType.SelectedIndex - 1);
             Buffer.BlockCopy(tmp, 0, bs, 5, 4);

             tmp = BitConverter.GetBytes((double)Math.Max(0, number));
             Buffer.BlockCopy(tmp, 0, bs, 9, 8);

             // send UDP command
             var client = new UdpClient();
             IPEndPoint ep = new IPEndPoint(Program.configuration.pluginAddress, Program.configuration.pluginPort);
             client.Connect(ep);

             // send data
             client.Send(bs, bs.Length);
             client.Close();
              */
            if (autoCameraEngine != null)
            {
                autoCameraEngine.Abort();
                autoCameraEngine = null;
            }

            if (cbAutoCameraMode.SelectedIndex == 1)
            {
                autoCameraEngine = new FocusLeaderCamera( cbAutoCameraType.SelectedIndex - 1, chkAutoExcludePit.Checked);
                autoCameraEngine.Start();
            }
            else if (cbAutoCameraMode.SelectedIndex == 2)
            {
                autoCameraEngine = new CycleTopDriversPerCategoryCamera( cbAutoCameraType.SelectedIndex - 1, chkAutoExcludePit.Checked, numberFreq, numberDriver);
                autoCameraEngine.Start();
            }
            else if (cbAutoCameraMode.SelectedIndex == 3)
            {
                autoCameraEngine = new CycleTopDriversCamera( cbAutoCameraType.SelectedIndex - 1, chkAutoExcludePit.Checked, numberFreq, numberDriver);
                autoCameraEngine.Start();
            }
            else if (cbAutoCameraMode.SelectedIndex == 4)
            {
                autoCameraEngine = new CycleAllDriversCamera( cbAutoCameraType.SelectedIndex - 1, chkAutoExcludePit.Checked, numberFreq);
                autoCameraEngine.Start();
            }
        }

        private void cbAutoCameraMode_SelectedIndexChanged(object sender, EventArgs e)
        {
            cbAutoCameraType.Enabled = cbAutoCameraMode.SelectedIndex > 0;
            chkAutoExcludePit.Enabled = cbAutoCameraMode.SelectedIndex > 0;
            txtAutoFrequencySecond.Enabled = cbAutoCameraMode.SelectedIndex >= 2;
            txtAutoNbDrivers.Enabled = cbAutoCameraMode.SelectedIndex >= 2 && cbAutoCameraMode.SelectedIndex != 4;
        }
    }
}
